﻿#region imports

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Query = Codeplex.ODataTFS.Model.Entities.Query;

#endregion

namespace Codeplex.ODataTFS.Model.Serialization
{
	public class TFSQueryProxy : TFSBaseProxy
	{
		public TFSQueryProxy(Uri uri, ICredentials credentials) : base(uri, credentials)
		{
		}

		public Query GetQuery(Guid id)
		{
			var workItemServer = TfsConnection.GetService<WorkItemStore>();
			string projectName;
			try
			{
				var query = workItemServer.GetQueryDefinition(id);
				projectName = query.Project.Name;
			}
			catch (ArgumentException)
			{
				// Weird bug in the TFS API, queries stored in TFS2008 cannot be accessed
				// using the new 2010 API, must use the old deprecated method.
#pragma warning disable
				var query = workItemServer.GetStoredQuery(id);
				projectName = query.Project.Name;
#pragma warning restore
			}

			return GetQueriesInHierarchy(workItemServer.Projects[projectName].QueryHierarchy, projectName)
				.SingleOrDefault(q => q.Id.Equals(id.ToString(), StringComparison.OrdinalIgnoreCase));
		}

		public IEnumerable<Query> GetQueriesByProjectCollection()
		{
			if (Cache[GetQueriesByProjectCollectionKey()] == null)
			{
				Cache[GetQueriesByProjectCollectionKey()] = RequestQueriesByProjectCollection();
			}

			return (IEnumerable<Query>) Cache[GetQueriesByProjectCollectionKey()];
		}

		public IEnumerable<Query> GetQueriesByProject(string projectName)
		{
			if (Cache[GetQueriesByProjectKey(projectName)] == null)
			{
				Cache[GetQueriesByProjectKey(projectName)] = RequestQueriesByProject(projectName);
			}

			return (IEnumerable<Query>) Cache[GetQueriesByProjectKey(projectName)];
		}

		private static List<Query> GetQueriesInHierarchy(IEnumerable<QueryItem> queries, string path = "")
		{
			var queryItems = new List<Query>();
			foreach (var queryItem in queries)
			{
				var queryPath = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", path, queryItem.Name);
				if (queryItem is QueryFolder)
				{
					queryItems.AddRange(GetQueriesInHierarchy(queryItem as QueryFolder, queryPath));
				}
				else
				{
					queryItems.Add((queryItem as QueryDefinition).ToModel(queryPath));
				}
			}

			return queryItems;
		}

		private IEnumerable<Query> RequestQueriesByProjectCollection()
		{
			var workItemServer = TfsConnection.GetService<WorkItemStore>();
			return workItemServer.Projects
				.Cast<Project>().Where(p => p.HasWorkItemReadRights)
				.SelectMany(p => GetQueriesInHierarchy(p.QueryHierarchy, p.Name));
		}

		private IEnumerable<Query> RequestQueriesByProject(string projectName)
		{
			var workItemServer = TfsConnection.GetService<WorkItemStore>();

			return GetQueriesInHierarchy(workItemServer.Projects[projectName].QueryHierarchy, projectName);
		}

		private string GetQueriesByProjectCollectionKey()
		{
			return "TFSQueryProxy.GetQueriesByProjectCollection";
		}

		private string GetQueriesByProjectKey(string projectName)
		{
			return string.Format(CultureInfo.InvariantCulture, "TFSQueryProxy.GetQueriesByProject_{0}", projectName);
		}
	}
}
